package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.model.behavior.pojos.ApBehaviorEntry;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.search.feign.BehaviorFeign;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.ArticleSearchService;
import com.heima.utils.threadlocal.AppThreadLocalUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @作者 itcast
 * @创建日期 2021/2/22 10:00
 **/
@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {
    @Autowired
    RestHighLevelClient restHighLevelClient;

    @Autowired
    ApUserSearchService apUserSearchService;

    @Autowired
    BehaviorFeign behaviorFeign;

    public static final String INDEX_NAME = "app_info_article";


    @Override
    public ResponseResult search(UserSearchDto userSearchDto) throws IOException {
        // 1. 检查参数 (keyword   最小时间  分页)
        if(userSearchDto == null || StringUtils.isBlank(userSearchDto.getSearchWords())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(userSearchDto.getMinBehotTime() == null){
            userSearchDto.setMinBehotTime(new Date());
        }
        if(userSearchDto.getPageSize() < 1){
            userSearchDto.setPageSize(10);
        }

        // 只有在搜索首页  才记录搜索历史
        if(userSearchDto.getFromIndex() == 0){
            ApBehaviorEntry entry = getEntry(userSearchDto);
            if(entry != null){
                apUserSearchService.insert(entry.getId(),userSearchDto.getSearchWords());
            }else {
                log.error("记录搜索历史失败，未获取到行为实体数据");
            }
        }
        // 2. 创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        // 3. 创建bool条件 ( must  mustnot  should  )
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 4. 关键词分词查询   查询title字段  content字段   采用or的关系
        QueryStringQueryBuilder stringQueryBuilder = QueryBuilders.queryStringQuery(userSearchDto.getSearchWords())
                .field("title")
                .field("content")
                .defaultOperator(Operator.OR);
        boolQueryBuilder.must(stringQueryBuilder);
        // 5. 时间范围查询   publishTime < minBehotTime
        RangeQueryBuilder publishTime = QueryBuilders.rangeQuery("publishTime").lt(userSearchDto.getMinBehotTime());
        boolQueryBuilder.filter(publishTime);
        builder.query(boolQueryBuilder);
        // 6. 按照发布时间降序 排序
        builder.sort("publishTime", SortOrder.DESC);
        //  标题要进行高亮处理 (高亮请求: 哪个字段高亮  添加的前置标签   添加的后置标签)
//        HighlightBuilder highlightBuilder = new HighlightBuilder();
//        highlightBuilder.field("title");
//        highlightBuilder.preTags("<span style='color:red'>");
//        highlightBuilder.postTags("</span>");
//        builder.highlighter(highlightBuilder);
        // 7. 取 pageSize条记录
        builder.from(0);
        builder.size(userSearchDto.getPageSize());
        // 8. 执行搜索请求
        searchRequest.source(builder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        // 9. 解析响应结果
        SearchHit[] hits = searchResponse.getHits().getHits();
        List<Map> mapList = new ArrayList();
        for (SearchHit docHit : hits) {
            Map map = JSON.parseObject(docHit.getSourceAsString(), Map.class);
            // key: 高亮处理字段名称  value：高亮的处理结果
//            Map<String, HighlightField> highlightFields = docHit.getHighlightFields();
//            // 高亮处理结果
//            HighlightField highlightField = highlightFields.get("title");
//            Text[] fragments = highlightField.getFragments();
//            map.put("title",StringUtils.join(fragments));
            mapList.add(map);
        }
        // 10。 返回
        return ResponseResult.okResult(mapList);
    }

    private ApBehaviorEntry getEntry(UserSearchDto userSearchDto) {
        ApUser user = AppThreadLocalUtils.getUser();
        return behaviorFeign.findByUserIdOrEntryId(user==null? 0 : user.getId() , userSearchDto.getEquipmentId());
    }

    @Override
    public void saveArticle(String articleId, Map article) throws IOException {
        IndexRequest request = new IndexRequest(INDEX_NAME);
        request.id(articleId); // 设置文章ID
        request.source(article); // 设置索引库文章内容
        restHighLevelClient.index(request,RequestOptions.DEFAULT);
    }
    @Override
    public void deleteArticle(String articleId) throws IOException {
        DeleteRequest request = new DeleteRequest(INDEX_NAME,articleId);
        restHighLevelClient.delete(request,RequestOptions.DEFAULT);
    }
}
